﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DDD.Core {


    /// <summary>
    /// LODセレクター・コンポーネント
    /// </summary>
    /// <remarks>
    /// ノードにアタッチしLOD選択機能を追加するコンポーネントの一種です。
    /// LODはノードの子ノードの中から距離に応じて適切な1つを自動で選んで描画する仕組みです。
    /// <para>
    /// LOD選択の仕組み
    /// LODはまず親ノードの<see cref="BoundingVolume"/>をスクリーンに投影しおおよそのピクセル数を計算します。
    /// 次にLOD候補になっている子ノードの中からこの推定解像度に一番近い子ノードを選択し有効にします。
    /// 残りの子ノードは全て無効化されます。
    /// </para>
    /// <para>
    /// ヒステリシスループ
    /// ヒステリシスループはLOD候補の切り替え付近で頻繁に2つのモデルが切り替わらないように、
    /// 一定の遷移領域を作る仕組みです。
    /// </para>
    /// </remarks>
    public class LODSelector : Component {

        #region Field
        List<LODCandidate> candidates;
        float hysterisys;
        #endregion

        #region Constructor
        /// <summary>
        /// コンストラクター
        /// </summary>
        public LODSelector () {
            this.candidates = new List<LODCandidate> ();
            this.hysterisys = 0;
        }
        #endregion

        #region Property

        /// <summary>
        /// LOD選択の候補になっているノードの数
        /// </summary>
        public int CandidateCount {
            get { return candidates.Count; }
        }

        /// <summary>
        /// すべてのLOD候補を列挙する列挙子
        /// </summary>
        public IEnumerable<LODCandidate> Candidates {
            get { return candidates; }
        }

        /// <summary>
        /// ヒステリシスループ
        /// </summary>
        /// <remarks>ヒステリシスループの大きさを割合[0,1]です。</remarks>
        public float Hysterisys {
            get { return hysterisys; }
        }

        /// <summary>
        /// このオブジェクトが参照する全DDDオブジェクトを列挙する列挙子
        /// </summary>
        /// <remarks>
        /// 参照にnullは含まれません。同一のオブジェクトが複数出現する可能性があります。
        /// </remarks>
        public override IEnumerable<Object> References {
            get {
                return base.References;
            }
        }
        #endregion

        #region Method

        /// <summary>
        /// LOD選択候補にノードを追加します
        /// </summary>
        /// <remarks>
        /// LOD選択候補としてセットできるのはノードの直接の子ノードだけです。
        /// 
        /// </remarks>
        /// <param name="node">ノード</param>
        /// <param name="resolution">目標解像度(ピクセル数)</param>
        public void AddCandidate (Node node, int resolution) {
            this.candidates.Add (new LODCandidate (node, resolution));
        }

        /// <summary>
        /// LOD選択候補から指定のノードを削除します
        /// </summary>
        /// <remarks>
        /// </remarks>
        /// <param name="node"></param>
        public void RemoveCandidate (Node node) {
        }

        /// <summary>
        /// LOD選択候補を取得します
        /// </summary>
        /// <param name="index">インデックス</param>
        /// <returns>ノード</returns>
        public LODCandidate GetCandidate (int index) {
            return candidates[index];
        }

        /// <summary>
        /// 最後に選択されたLOD候補を取得します
        /// </summary>
        /// <remarks>
        /// 一番最後に呼ばれた<see cref="World.Select"/>で選択されたLOD候補のノードを返します。
        /// </remarks>
        /// <returns></returns>
        public Node GetSeletedNode () {
            return null;
        }

        /// <summary>
        /// 最後にLOD選択を行ったときの推定解像度を取得します
        /// </summary>
        /// <remarks>
        /// 一番最後に呼ばれた<see cref="World.Select"/>で計算された推定解像度を返します。
        /// </remarks>
        /// <returns></returns>
        public int GetEstimatedResolution() {
            return 0;
        }

        /// <summary>
        /// ヒステリシスループの設定
        /// </summary>
        /// <remarks>
        /// LOD選択は頻繁に切り替えが発生しないようにヒステリシスループという仕組みが実装されています。
        /// </remarks>
        /// <param name="hys">ヒステリシスループ[0,1]</param>
        public void SetHysterisis (float hys) {
            this.hysterisys = hys;
        }

        /// <summary>
        /// LOD選択処理を行いただ1つの子ノードを有効化します
        /// </summary>
        public void OnSelect () {

        }

        /// <summary>
        /// 現在のオブジェクトの状態を表す文字列を返します。
        /// </summary> 
        public override string ToString () {
            return string.Format("LODSelector: Candidates={0}", CandidateCount);
        }

        #endregion

    }
}
